<!-- eslint-disable vue/no-lone-template -->
<template>
	<div class="form-box" v-if="itemForm.length">
		<el-form ref="ruleFormRef" :model="formParam" label-width="auto">
			<el-row :gutter="20">
				<!-- 表单上面插槽 -->
				<slot name="formtop"></slot>
				<el-col v-for="(item, index) in itemBox" :key="item.prop" v-bind="item.layoutCol ?? layoutCol" :index="index">
					<el-form-item
						:label="`${item.label ? item.label + ' :' : item.label}`"
						:required="item.required"
						:class="item.labelClass"
						:rules="item.rules"
						:prop="item.prop"
					>
						<!-- 表单下面的提示插槽 -->
						<slot :name="`${item.prop}slot`">
							<template :v-slot="`${item.prop}slot`"> </template>
						</slot>
						<!-- 自定义表单插槽 -->
						<slot :name="item.prop">
							<form-item :column="item" :formParam="formParam" @focus-form="item.focusForm" @change-form="item?.changeForm">
							</form-item>
						</slot>
					</el-form-item>
				</el-col>
				<!-- 表单下面插槽 -->
				<slot name="formbottom"></slot>
			</el-row>
			<div class="form-btn" v-if="isShowBtn">
				<el-button @click="cancelForm(ruleFormRef)" v-if="isShowCancelBtn">{{ cancelBtnText }}</el-button>
				<el-button plain @click="resetForm(ruleFormRef)" v-if="isShowResetBtn">{{ resetBtnText }}</el-button>
				<el-button type="primary" :loading="submitting" @click="submitForm(ruleFormRef)">{{ sureBtnText }}</el-button>
			</div>
		</el-form>
	</div>
</template>
<script setup lang="ts" name="FormBox">
import { computed, ref, reactive, provide } from 'vue';
import { FromBoxProps, FormParam } from '@/components/FormBox/interface';
import FormItem from './components/FormItem.vue';
import type { FormInstance } from 'element-plus';
// typescript 后缀 "!"操作符 去掉值是null和undefined
// 用于提交时的校验
const ruleFormRef = ref<FormInstance>();
const formParam = reactive<FormParam>({});
const newFormParam = reactive<FormParam>({});
interface FormBoxProps {
	itemForm?: FromBoxProps[]; // 表单配置列
	sureBtnText?: string; // 提交按钮文字
	isShowBtn?: boolean; // 是否展示按钮
	cancelBtnText?: string; // 不是提交按钮文字
	isShowCancelBtn?: boolean; // 是否展示取消或者返回按钮
	isShowResetBtn?: boolean; // 是否展示重置按钮
	resetBtnText?: string; // 重置按钮文字
	submitting?: boolean; // 提交时的加载效果
	submitForm?: (params: any) => void; // 表单提交
	resetForm?: () => void; // 重置方法
	closeForm?: () => void; // 重置方法
	isResetAllForm?: boolean; // 是否重置所有表单
	pageFormParam?: any; // isResetAllForm为false的时候需求回填表单
}

// 定义 enumMap 存储 enum 值（避免异步请求无法格式化单元格内容 || 无法填充组件数据）
const enumMap = ref(new Map<string, { [key: string]: any }[]>());
provide('enumMap', enumMap);

// 默认值
const props = withDefaults(defineProps<FormBoxProps>(), {
	itemForm: () => [],
	sureBtnText: '保存',
	cancelBtnText: '取消',
	resetBtnText: '重置',
	submitForm: () => {},
	resetForm: () => {},
	closeForm: () => {},
	submitting: false,
	isShowBtn: true,
	isShowCancelBtn: true,
	isShowResetBtn: false,
	isResetAllForm: true
});
// console.log(JSON.stringify(props.itemForm));

const itemBox = computed(() => {
	props.itemForm.forEach(async item => {
		// 如果当前 enum 为后台数据需要请求数据，则调用该请求接口，并存储到 enumMap
		if (typeof item.enum === 'function') {
			const { data } = await item.enum();
			// 过滤字典数据
			let enumData: any[] = [];
			if (item?.enumParams) {
				enumData = data.filter((items: any) => {
					return item?.enumParams === items.dicTypeCode;
				});
				// 过滤字典中某些值
				if (item?.form?.filterDict && item?.form?.filterDict?.length > 0) {
					enumData = enumData.filter((items: any) => {
						return !item?.form?.filterDict?.includes(items.value);
					});
				}
			} else {
				enumData = data;
			}

			enumMap.value.set(item.prop!, enumData);
		} else if (item.enum && typeof item.enum !== 'function') {
			enumMap.value.set(item.prop!, item.enum);
		}
		// 设置默认值
		if (item.form?.defaultValue) {
			formParam[item.prop] = item.form?.defaultValue;
		}
	});
	// 过滤掉需要隐藏的表单
	const data = props.itemForm.filter(item => {
		return !item?.hidden;
	});
	return data;
});

// 提交
const submitForm = async (formEl: FormInstance | undefined) => {
	if (!formEl) return;
	await formEl.validate((valid, fields) => {
		if (valid) {
			// console.log(formParam);
			for (const key in formParam) {
				// 这里需要newFormParam去接收不然会影响表单
				newFormParam[key] = formParam[key];
				itemBox.value.map((item: any) => {
					// 处理上传文件数据
					if (key === item.prop && item.form?.props?.type === 'ZhyUploadFile' && formParam[key]?.length > 0) {
						newFormParam[item.prop] = formParam[key]
							.map((itemC: any) => {
								// 处理回填文件
								if (itemC.url && itemC.url.indexOf('download/') !== -1) {
									let fileUrl: string = '';
									const sUrl: string[] = itemC.url.split('download/');
									if (sUrl[1]) {
										fileUrl = sUrl[1].split('?watermark')[0];
									}
									return fileUrl;
								}
								return itemC.response?.data ?? itemC.url;
							})
							.join(',');
					} else if (key === item.prop && item.form?.props?.type === 'datetimerange' && formParam[key]?.length > 0) {
						// 时间范围处理数据
						if (item.keyRange?.length > 0) {
							console.log(formParam[key]);
							newFormParam[item.keyRange[0]] = formParam[key][0];
							newFormParam[item.keyRange[1]] = formParam[key][1];
							delete newFormParam[item.prop];
						}
					}
				});
			}
			props.submitForm(newFormParam);
			console.log('submit!');
		} else {
			console.log('error submit!', fields);
		}
	});
};
// 重置表单, 默认值的除外
const resetForm = async (formEl: FormInstance | undefined, isResetAll = false) => {
	if (!formEl) return;
	if (props.isResetAllForm || isResetAll) {
		await formEl.resetFields();
	} else {
		formEl.clearValidate();
		Object.assign(formParam, {
			...props?.pageFormParam
		});
	}
	props.resetForm();
};

const cancelForm = (formEl: FormInstance | undefined) => {
	if (!formEl) return;
	formEl.resetFields();
	props.closeForm();
};

// 初始化赋值用defaultValue, 其他的赋值用formParam[prop]
// 如果是表单需要处理的用newFormParam
defineExpose({
	formParam,
	newFormParam,
	resetForm,
	ruleFormRef
});

// 默认值
const layoutCol = { sm: 24, md: 24, lg: 24, xl: 24 };
</script>
<style lang="scss" scoped>
.form-box {
	:deep(.el-select) {
		width: 100%;
	}
	:deep(span) {
		font-size: var(--el-font-size-base) !important;
	}
	.form-btn {
		text-align: right;
	}
	:deep(.el-date-editor.el-input, .el-date-editor.el-input__wrapper, .el-input-number) {
		width: 100%;
	}
	:deep(.el-input-number) {
		width: 100%;
	}
}
</style>
